import { Prop, Emit, Watch, ComponentBase, Ref } from 'vue-facing-decorator'
import Render from '@/render/Render'
import toNative from '@/utils/toNative'
import { shake, wait } from '@/utils/util'
import { nextTick, type ComponentPublicInstance, type VNode } from 'vue'
import { Button, Image, message, Upload, type UploadFile } from 'ant-design-vue'
import type { UploadChangeParam } from 'ant-design-vue/es/upload/interface'
import { DeleteOutlined, EyeOutlined, UploadOutlined } from '@ant-design/icons-vue'

export interface UploadFileDto extends UploadFile {
    fullBase64?: string
    base64?: string
    isCover?: boolean | string
    isChoose?: boolean
}

export interface ParamsDto {
    autoUpload: boolean
    accept: string
    limit: number
    maxSize: number
    base64: boolean
    listType: 'text' | 'picture' | 'picture-card'
    text: string
    hint: string
    hideListType: boolean
    exit: number
}

@ComponentBase
export class FileUpload extends Render {
    fileList = [] as UploadFileDto[] | string[]

    @Prop() params?: ParamsDto
    @Prop() modelValue!: string | string[]
    @Prop() multiple!: boolean

    visible = false
    previewSrc = ''

    uploadedUrl: string[] = []

    get actionUrl() {
        return this.params?.autoUpload ? '/crm-prod-v2/web/common/oss/upload' : '#'
    }

    @Emit('update:modelValue')
    handleEmit() {
        console.log(1111, this.fileList)
        if (this?.params?.base64) {
            return (this.fileList as UploadFileDto[]).map((item) => item.url || item.base64)
        }
        if (this.params?.autoUpload && !this.params?.base64) {
            return (this.fileList as UploadFileDto[]).map(i => i.response?.data ?? i.url)
        }
        return this.fileList
    }

    @Emit('change')
    handleChange(fileList: UploadFileDto[]) {
        if (this?.params?.base64) {
            return fileList.map((item) => item.url || item.base64)
        }
        return fileList
    }

    @Watch('modelValue', { immediate: true, deep: true })
    handleWatchModelValue(val: string | string[] | UploadFileDto[]) {
        if (!val?.length) {
            this.fileList = []
            return
        }
        if (
            val?.length === this.fileList?.length &&
            val[0] === ((this.fileList as UploadFileDto[])[0]?.url || (this.fileList as UploadFileDto[])[0]?.base64)
        ) {
            return
        }
        const valueList = Array.isArray(val) ? val : [val]
        valueList.forEach((item, index) => {
            if (!(item as UploadFileDto)?.uid) {
                const isUrl = (item as string).startsWith('http')
                const nameStart = (item as string).lastIndexOf('/')
                this.fileList = []
                ;(this.fileList as UploadFileDto[]).push({
                    uid: index.toString(),
                    name: (item as string).substring(nameStart + 1),
                    url: isUrl ? item : `data:image/png;base64,${item}`,
                    thumbUrl: isUrl ? item : `data:image/png;base64,${item}`
                } as UploadFileDto)
            }
        })
    }

    async onChange(info: UploadChangeParam<UploadFileDto>) {
        info.fileList.forEach(async (item) => {
            item.fullBase64 = (await this.getBase64(item.originFileObj as File)) as string
            item.base64 = item.fullBase64?.split(';base64,')?.[1] ?? ''
        })
        await wait(300)
        if (!this.params?.autoUpload) {
            this.handleChange(info.fileList)
            this.handleEmit()
            return
        }
        if (this.params?.autoUpload && (info.file?.status === 'done' || info?.file?.url)) {
            this.handleChange(info.fileList)
            this.handleEmit()
        }
    }

    async onRemove() {
        console.log(12345, this.fileList)
        // await wait(300)
        // this.handleEmit()
    }

    getBase64(raw: File) {
        return new Promise((resolve) => {
            const imgFile = new FileReader()
            imgFile.readAsDataURL(raw)
            imgFile.onload = (res) => {
                const base64 = res?.target?.result as string
                resolve(base64)
            }
        })
    }

    beforeUpload(file: UploadFileDto) {
        // 限制上传数量
        if (this.fileList.length > (this.params?.limit || 1)) {
            message.error('最多上传' + (this.params?.limit || 1) + '张图片')
            return false
        }
        if (
            this.params?.hideListType &&
            this.params?.limit &&
            this.params?.exit &&
            this.params.exit > this.params.limit
        ) {
            message.error('最多上传' + (this.params?.limit || 1) + '张图片')
            return false
        }
        // 限制上传大小
        const maxSize = this.params?.maxSize || 5
        if ((file.size as number) > maxSize * 1024 * 1024) {
            message.error(`上传图片大小不能超过${maxSize}M`)
            return Upload.LIST_IGNORE
        }
        return this.params?.autoUpload ?? false
    }

    onPreview(url: string) {
        this.visible = true
        this.previewSrc = url
    }

    onMounted() {
        console.log('reload')
    }

    render(data: ComponentPublicInstance) {
        return (
            <div>
                <Upload
                    v-model:file-list={this.fileList}
                    action={this.actionUrl}
                    beforeUpload={this.beforeUpload}
                    accept={this.params?.accept}
                    listType={this.params?.listType || 'text'}
                    maxCount={this.params?.limit || 1}
                    multiple={this.multiple || false}
                    onChange={this.onChange}
                    onRemove={this.onRemove}
                    v-slots={{
                        default: () => {
                            return (
                                data?.$slots?.default?.() ?? (
                                    <div
                                        class={`${this.params?.listType !== 'picture-card' ? '!w-340px py-10px rounded-sm border-1 border-solid bg-black-400 border-border-color' : ''}`}
                                    >
                                        <div class="flex items-center justify-center">
                                            <UploadOutlined class="text-blue-100" />
                                            <div class="ml-8px text-base">
                                                {this.params?.text ?? '上传'}
                                            </div>
                                        </div>
                                        <div class="text-sm text-black-300 text-center mt-5px">
                                            {this.params?.hint}
                                        </div>
                                    </div>
                                )
                            )
                        },
                        itemRender: ({
                            file,
                            actions
                        }: {
                            originNode: VNode
                            file: UploadFile & { fullBase64: string }
                            fileList: object[]
                            actions: { download: () => void; preview: () => void; remove: () => void }
                        }) => {
                            const listType = this.params?.listType || 'text'
                            return listType === 'text' ? (
                                <div class="flex items-center justify-between mt-10px">
                                    <span
                                        class="cursor-pointer"
                                        onClick={() =>
                                            this.onPreview((file.url || file.fullBase64) as string)
                                        }
                                    >
                                        {file.name}
                                    </span>
                                    <div class="cursor-pointer" onClick={actions.remove}>
                                        <DeleteOutlined />
                                    </div>
                                </div>
                            ) : listType === 'picture' ? (
                                <div class="flex items-center justify-between mt-10px">
                                    <div class="flex items-center">
                                        <Image
                                            class="!w-48px !h-48px rounded-sm"
                                            src={file.url || file.fullBase64}
                                            preview={{ src: file.url || file.fullBase64 }}
                                        />
                                        <span class="ml-10px">{file.name}</span>
                                    </div>
                                    <div class="cursor-pointer" onClick={actions.remove}>
                                        <DeleteOutlined />
                                    </div>
                                </div>
                            ) : listType === 'picture-card' ? (
                                <Image
                                    class="!w-100px !h-100px border-1 overflow-hidden border-solid rounded-sm border-border-color-100"
                                    preview={{ src: (file.url || file.fullBase64) as string }}
                                    src={(file.url || file.fullBase64) as string}
                                    v-slots={{
                                        previewMask: () => {
                                            return (
                                                <div class="flex justify-between gap-20px">
                                                    <div>
                                                        <EyeOutlined />
                                                    </div>
                                                    <div onClick={actions.remove}>
                                                        <DeleteOutlined />
                                                    </div>
                                                </div>
                                            )
                                        }
                                    }}
                                />
                            ) : (
                                <></>
                            )
                        }
                    }}
                ></Upload>
                <Image
                    style={{ display: 'none' }}
                    src={this.previewSrc}
                    preview={{
                        visible: this.visible,
                        onVisibleChange: (val) => {
                            this.visible = val
                        }
                    }}
                ></Image>
            </div>
        )
    }
}

export default toNative<
    { params: Partial<ParamsDto>; multiple?: boolean },
    {
        change: (fileList: UploadFileDto[]) => void
            }
            >(FileUpload)
